package com.minisoft.utils;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.minisoft.pool.MpUserEventDto;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.initialization.qual.Initialized;
import org.junit.Before;
import org.junit.Test;
import org.redisson.Redisson;
import org.redisson.api.ExpiredObjectListener;
import org.redisson.api.ObjectListener;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.lang.reflect.Field;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * @author JueSu
 * @description: TODO
 * @date 2022/10/27 8:26
 */
@Slf4j
//@Component
public class RedisTest {

    private RedissonClient redissonClient;

    @Before
    @PostConstruct
    public void init() {
        RedissonProperties redissonProperties = new RedissonProperties();
        Config config = new Config();
        config.useSingleServer()
                .setAddress("redis://" + redissonProperties.getHost() + ":" + redissonProperties.getPort())
                .setDatabase(redissonProperties.getDatabase())
                .setConnectionPoolSize(1000);
        redissonClient =  Redisson.create(config);
        log.info("init redissonClient ok");
    }

    CountDownLatch countDownLatch = new CountDownLatch(1);


    @Test
    public void testTTL() throws InterruptedException {
        RBucket<Object> testTTL = redissonClient.getBucket("testTTL");
        if (testTTL.get() == null) {
            JSONObject o = new JSONObject();
            o.set("id",1).set("name","name");
            testTTL.set(o,120, TimeUnit.SECONDS);
            testTTL.addListener(new ExpiredObjectListener() {
                @Override
                public void onExpired(String s) {
                    log.info("expire {}",s);
                }
            });
            log.info("add obj");
        } else {
            JSONObject o = (JSONObject) testTTL.get();
            long remainTimeToLive = testTTL.remainTimeToLive();
            o.set("name","name2");
            testTTL.set(o,remainTimeToLive,TimeUnit.MILLISECONDS);
            log.info("update obj");
            testTTL.addListener(new ExpiredObjectListener() {
                @Override
                public void onExpired(String s) {
                    log.info("expire {}",s);//testTTL
                }
            });
        }
        countDownLatch.await();
    }

    public void cacheUserInfo(MpUserEventDto mpUserEventDto) {
        String redisKeyUser = "mp:pool:userinfo:" + mpUserEventDto.getUnionId();
        String redisKeyUserInfo = redisKeyUser + "_user_info";
        RBucket<MpUserEventDto> bucketUser = redissonClient.getBucket(redisKeyUserInfo);
        MpUserEventDto cacheUser = bucketUser.get();
        log.info("bucketUser.normal = " + bucketUser);
        if (cacheUser == null) {//说明没有缓存，放入缓存
            RBucket<Integer> bucketKey = redissonClient.getBucket(redisKeyUser);
            bucketKey.set(1,10,TimeUnit.SECONDS);
            //增加监听器，重启后，这个事件会失效
            int eventHashCode = bucketKey.addListener(new ExpiredObjectListener() {
                public void onExpired(String key) {
                    RBucket<MpUserEventDto> bucketUser = redissonClient.getBucket(key + "_user_info");
                    log.info("bucketUser.back = " + bucketUser);
                    MpUserEventDto user = bucketUser.get();
                    if (user == null) {
                        log.info("无法获取用户信息，跳过上报");
                        return;
                    }
                    try {
                        String bodyStr = JSONUtil.toJsonStr(user);
                        //mqProducer.sendCpMessage(bodyStr);
                        bucketUser.delete();
                        log.info("缓存完成上报潜客池并删除缓存用户信息，{}", bodyStr);
                    } finally {
                        bucketKey.removeListener(user.getEventHashCode());
                    }
                }
            });
            log.info("eventHashCode，{}",eventHashCode);

            mpUserEventDto.setEventHashCode(eventHashCode);
            //多放3秒，回调时能获取到数据
            bucketUser.set(mpUserEventDto,10 + 3,TimeUnit.SECONDS);
            log.info("重新设置缓存数据，{}",JSONUtil.toJsonStr(mpUserEventDto));
        } else {
            long remainTimeToLive = bucketUser.remainTimeToLive();
            //合并用户信息，只设置新数据
            compackInfo(mpUserEventDto,cacheUser);
            log.info("合并用户信息，只设置新数据：{}",JSONUtil.toJsonStr(cacheUser));
            bucketUser.set(cacheUser,remainTimeToLive,TimeUnit.MILLISECONDS);
        }
    }

    private void compackInfo(MpUserEventDto mpUserEventDto, MpUserEventDto cacheUser) {
        Field[] fields = ReflectUtil.getFields(MpUserEventDto.class);
        for (Field field : fields) {
            Object fieldValue = ReflectUtil.getFieldValue(cacheUser, field);
            //如果旧值没有，新值有，则获取新值
            if (ObjectUtils.isEmpty(fieldValue)) {
                Object fieldValue2 = ReflectUtil.getFieldValue(mpUserEventDto, field);
                if (ObjectUtils.isNotEmpty(fieldValue2)) {
                    ReflectUtil.setFieldValue(cacheUser,field,fieldValue2);
                }
            }
        }
    }
}
